package com.doudou.collection.infrastructure.core.service;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.doudou.collection.infrastructure.common.security.CurrentPrincipal;
import com.doudou.collection.infrastructure.common.web.ResultVO;
import com.doudou.collection.infrastructure.common.web.StatusCode;
import com.doudou.collection.infrastructure.core.security.CustomUserDetails;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName TokenService<br>
 * @Description token验证处理<br>
 * @Author 李浩文<br>
 * @Date 2023/6/26 11:05<br>
 * @Version 1.0<br>
 */
@Slf4j
@Component
public class TokenService {

    /**
     * 自定义令牌标识
     */
    @Value("${token.header}")
    private String header;

    /**
     * 令牌秘钥
     */
    @Value("${token.secret}")
    private String secretKey;

    @Value("${token.duration-in-minute}")
    private Long durationInMinute;


    /**
     * 获取用户身份信息
     *
     * @return 用户信息
     */
    public CurrentPrincipal getLoginUser(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 获取请求携带的令牌
        String token = getToken(request);
        if (StrUtil.isNotEmpty(token)) {
            try {
                log.debug("尝试解析JWT数据……");
                response.setContentType("application/json; charset=utf-8");
                Claims claims = parseToken(token);
                // 从解析结果中获取用户的信息
                return setLoginUser(claims);
            } catch (ExpiredJwtException e) {
                log.warn("解析JWT时出现异常：ExpiredJwtException");
                String message = "操作失败，您的登录信息已经过期，请重新登录！";
                ResultVO resultVO = ResultVO.error(StatusCode.ERROR_UPDATE, message);
                PrintWriter writer = response.getWriter();
                writer.println(JSON.toJSONString(resultVO));
                writer.close();
            } catch (MalformedJwtException e) {
                log.warn("解析JWT时出现异常：MalformedJwtException");
                String message = "非法访问，你的本次操作已经被记录！";
                ResultVO resultVO = ResultVO.error(StatusCode.ERROR_UPDATE, message);
                PrintWriter writer = response.getWriter();
                writer.println(JSON.toJSONString(resultVO));
                writer.close();
            } catch (SignatureException e) {
                log.warn("解析JWT时出现异常：SignatureException");
                String message = "非法访问，你的本次操作已经被记录！";
                ResultVO resultVO = ResultVO.error(StatusCode.ERROR_UPDATE, message);
                PrintWriter writer = response.getWriter();
                writer.println(JSON.toJSONString(resultVO));
                writer.close();
            } catch (Throwable e) {
                log.warn("解析JWT时出现异常：{}", e);
                String message = "服务器忙，请稍后再试！【同学们，看到这句时，你应该检查服务器端的控制台，并在JwtAuthorizationFilter中解析JWT时添加处理异常的catch代码块】";
                ResultVO resultVO = ResultVO.error(StatusCode.ERROR_UPDATE, message);
                PrintWriter writer = response.getWriter();
                writer.println(JSON.toJSONString(resultVO));
                writer.close();
            }
        }
        return null;
    }

    /**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     * @return 数据声明
     */
    private Claims parseToken(String token) {
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 创建令牌
     *
     * @param loginUser 用户信息
     * @return 令牌
     */
    public String createToken(CustomUserDetails loginUser) {
        Date date = new Date(System.currentTimeMillis() + 1L * 60 * 1000 * durationInMinute);
        //                                                 ↑ 注意加L，避免int溢出为负数
        Map<String, Object> claims = new HashMap<>();
        //Collection<? extends GrantedAuthority> authorities = loginUser.getAuthorities();
        //将权限列表对象转换为JSON格式的字符串
        //String authoritiesJsonString = JSON.toJSONString(authorities);

        claims.put("id", loginUser.getId());
        claims.put("username", loginUser.getUsername());
        //claims.put("authoritiesJsonString", authoritiesJsonString);
        String jwt = Jwts.builder()
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                .setClaims(claims)
                .setExpiration(date)
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
        return jwt;
    }

    /**
     * 设置用户身份信息
     */
    public CurrentPrincipal setLoginUser(Claims claims) {
        Long id = claims.get("id", Long.class);
        String username = claims.get("username", String.class);
        String authoritiesJsonString = claims.get("authoritiesJsonString", String.class);
        List<SimpleGrantedAuthority> simpleGrantedAuthorities =
                JSON.parseArray(authoritiesJsonString, SimpleGrantedAuthority.class);

        CurrentPrincipal currentPrincipal = new CurrentPrincipal();
        currentPrincipal.setUserId(id);
        currentPrincipal.setUsername(username);
        currentPrincipal.setPermissions(simpleGrantedAuthorities);
        return currentPrincipal;
    }

        /**
         * 获取请求token
         *
         * @param request
         * @return token
         */
    private String getToken(HttpServletRequest request) {
        String token = request.getHeader(header);
        //TODO
        return token;
    }
}
